﻿using Newtonsoft.Json;
using System.Data;
using System.Text;

namespace ExcelToJson
{
    public class JsonDataHolder
    {
        public List<object>? configList;
    }

    /// <summary>
    /// 将DataTable对象，转换成JSON string，并保存到文件中
    /// </summary>
    internal class JsonGenerator
    {
        private Dictionary<string, Dictionary<string, object>> m_data;

        /// <summary>
        /// 构造函数：完成内部数据创建
        /// </summary>
        /// <param name="sheet">ExcelReader创建的一个表单</param>
        /// <param name="headerRows">表单中的那几行是表头</param>
        public JsonGenerator(DataTable sheet, int headerRows, bool lowcase)
        {
            if (sheet.Columns.Count <= 0)
            {
                throw new Exception(sheet.TableName + "列数<=0");
            }
            if (sheet.Rows.Count <= 0)
            {
                throw new Exception(sheet.TableName + "行数<=0");
            }

            m_data = new Dictionary<string, Dictionary<string, object>>();

            //field名
            DataRow fieldNameRow = sheet.Rows[0];

            //field类型
            DataRow fieldTypeRow = sheet.Rows[1];

            //--以第一列为ID，转换成ID->Object的字典
            int firstDataRow = headerRows;// - 1;

            for (int i = firstDataRow; i < sheet.Rows.Count; i++)
            {
                DataRow row = sheet.Rows[i];
                string ID = row[sheet.Columns[0]].ToString();
                if (string.IsNullOrEmpty(ID))
                {
                    continue;
                }

                var rowData = new Dictionary<string, object>();
                foreach (DataColumn column in sheet.Columns)
                {
                    object type = fieldTypeRow[column];
                    object? value = row[column];

                    if (type.GetType() == typeof(DBNull))
                    {
                        continue;
                    }

                    try
                    {
                        switch ((string)type)
                        {
                            case "int":
                                {
                                    if (value == null || value.GetType() == typeof(DBNull))
                                    {
                                        value = 0;
                                    }
                                    else if (value.GetType() == typeof(double))
                                    {
                                        double doubleValue = (double)value;
                                        value = (int)doubleValue;
                                    }
                                    else if (value.GetType() == typeof(string))
                                    {
                                        int intValue = int.Parse((string)value);
                                        value = intValue;
                                    }
                                }
                                break;

                            case "int[]":
                                {
                                    if (value == null || value.GetType() == typeof(DBNull))
                                    {
                                        value = null;
                                    }
                                    else
                                    {
                                        List<int> intList = new List<int>();
                                        string strValue = ToStringValue(value);

                                        //-1是个潜规则,等价于不填内容.
                                        if (strValue != "-1")
                                        {
                                            string[] strArr = (strValue).Split(";".ToCharArray());
                                            for (int index = 0; index < strArr.Length; index++)
                                            {
                                                if (string.IsNullOrEmpty(strArr[index]))
                                                {
                                                    continue;
                                                }

                                                intList.Add(int.Parse(strArr[index]));
                                            }
                                        }

                                        value = (intList.Count == 0) ? null : intList;
                                    }
                                }
                                break;

                            case "uint":
                                {
                                    if (value == null || value.GetType() == typeof(DBNull))
                                    {
                                        value = 0;
                                    }
                                    else if (value.GetType() == typeof(double))
                                    {
                                        double doubleValue = (double)value;
                                        value = (uint)doubleValue;
                                    }
                                    else if (value.GetType() == typeof(string))
                                    {
                                        uint intValue = uint.Parse((string)value);
                                        value = intValue;
                                    }
                                }
                                break;

                            case "uint[]":
                                {
                                    if (value == null || value.GetType() == typeof(DBNull))
                                    {
                                        value = null;
                                    }
                                    else
                                    {
                                        List<uint> intList = new List<uint>();
                                        string strValue = ToStringValue(value);

                                        if (strValue != "-1")
                                        {
                                            string[] strArr = (strValue).Split(";".ToCharArray());
                                            for (int index = 0; index < strArr.Length; index++)
                                            {
                                                if (string.IsNullOrEmpty(strArr[index]))
                                                {
                                                    continue;
                                                }

                                                intList.Add(uint.Parse(strArr[index]));
                                            }
                                        }

                                        value = (intList.Count == 0) ? null : intList;
                                    }
                                }
                                break;

                            case "double":
                                {
                                    if (value == null || value.GetType() == typeof(DBNull))
                                    {
                                        value = 0;
                                    }
                                    else if (value.GetType() == typeof(double))
                                    {
                                        //不需要做什么
                                    }
                                    else if (value.GetType() == typeof(string))
                                    {
                                        string strValue = (string)value;
                                        value = double.Parse(strValue);
                                    }
                                }
                                break;

                            case "double[]":
                                {
                                    if (value == null || value.GetType() == typeof(DBNull))
                                    {
                                        value = null;
                                    }
                                    else
                                    {
                                        List<double> longList = new List<double>();
                                        string strValue = ToStringValue(value);

                                        if (strValue != "-1")
                                        {
                                            string[] strArr = (strValue).Split(";".ToCharArray());
                                            for (int index = 0; index < strArr.Length; index++)
                                            {
                                                if (string.IsNullOrEmpty(strArr[index]))
                                                {
                                                    continue;
                                                }

                                                longList.Add(double.Parse(strArr[index]));
                                            }
                                        }

                                        value = (longList.Count == 0) ? null : longList;
                                    }
                                }
                                break;

                            case "long":
                                {
                                    if (value == null || value.GetType() == typeof(DBNull))
                                    {
                                        value = 0;
                                    }
                                    else if (value.GetType() == typeof(double))
                                    {
                                        double doubleValue = (double)value;
                                        value = (long)doubleValue;
                                    }
                                    else if (value.GetType() == typeof(string))
                                    {
                                        long intValue = long.Parse((string)value);
                                        value = intValue;
                                    }
                                }
                                break;

                            case "long[]":
                                {
                                    if (value == null || value.GetType() == typeof(DBNull))
                                    {
                                        value = null;
                                    }
                                    else
                                    {
                                        List<long> longList = new List<long>();
                                        string strValue = ToStringValue(value);

                                        if (strValue != "-1")
                                        {
                                            string[] strArr = (strValue).Split(";".ToCharArray());
                                            for (int index = 0; index < strArr.Length; index++)
                                            {
                                                if (string.IsNullOrEmpty(strArr[index]))
                                                {
                                                    continue;
                                                }

                                                longList.Add(long.Parse(strArr[index]));
                                            }
                                        }

                                        value = (longList.Count == 0) ? null : longList;
                                    }
                                }
                                break;

                            case "bool":
                                {
                                    if (value == null || value.GetType() == typeof(DBNull))
                                    {
                                        value = false;
                                    }
                                    else if (value.GetType() == typeof(bool))
                                    {
                                        value = (bool)value;
                                    }
                                    else if (value.GetType() == typeof(double))
                                    {
                                        double doubleValue = (double)value;
                                        value = (doubleValue == 0) ? false : true;
                                    }
                                    else if (value.GetType() == typeof(string))
                                    {
                                        string strValue = (string)value;
                                        value = bool.Parse(strValue);
                                    }
                                }
                                break;

                            case "bool[]":
                                {
                                    if (value == null || value.GetType() == typeof(DBNull))
                                    {
                                        value = null;
                                    }
                                    else
                                    {
                                        List<bool> boolArr = new List<bool>();
                                        string strValue = ToStringValue(value);
                                        if (strValue != "-1")
                                        {
                                            string[] strArr = (strValue).Split(";".ToCharArray());
                                            for (int index = 0; index < strArr.Length; index++)
                                            {
                                                if (string.IsNullOrEmpty(strArr[index]))
                                                {
                                                    continue;
                                                }

                                                bool boolValue = false;
                                                int intValue = 0;
                                                if (bool.TryParse(strArr[index], out boolValue))
                                                {
                                                    boolArr.Add(bool.Parse(strArr[index]));
                                                }
                                                else if (int.TryParse(strArr[index], out intValue))
                                                {
                                                    boolArr.Add(int.Parse(strArr[index]) == 0 ? false : true);
                                                }
                                            }
                                        }
                                        value = (boolArr.Count == 0) ? null : boolArr;
                                    }
                                }
                                break;

                            case "string":
                                {
                                    if (value == null || value.GetType() == typeof(DBNull))
                                    {
                                        value = null;
                                    }
                                    else
                                    {
                                        string strValue = ToStringValue(value);
                                        value = strValue;
                                    }
                                }
                                break;

                            case "string[]":
                                {
                                    if (value == null || value.GetType() == typeof(DBNull))
                                    {
                                        value = null;
                                    }
                                    else
                                    {
                                        List<string> strArray = new List<string>();
                                        string strValue = ToStringValue(value);
                                        if (strValue != "-1")
                                        {
                                            string[] strs = (strValue).Split(";".ToCharArray());
                                            for (int index = 0; index < strs.Length; index++)
                                            {
                                                if (string.IsNullOrEmpty(strs[index]))
                                                {
                                                    continue;
                                                }
                                                strArray.Add(strs[index]);
                                            }
                                        }
                                        value = (strArray.Count == 0) ? null : strArray;
                                    }
                                }
                                break;

                            case "float":
                                {
                                    if (value == null || value.GetType() == typeof(DBNull))
                                    {
                                        value = 0f;
                                    }
                                    else if (value.GetType() == typeof(double))
                                    {
                                        double doubleValue = (double)value;
                                        value = (float)doubleValue;
                                    }
                                    else if (value.GetType() == typeof(string))
                                    {
                                        double doubleValue = double.Parse((string)value);
                                        value = (float)doubleValue;
                                    }
                                }
                                break;

                            case "float[]":
                                {
                                    if (value == null || value.GetType() == typeof(DBNull))
                                    {
                                        value = null;
                                    }
                                    else
                                    {
                                        List<float> floatArr = new List<float>();
                                        string strValue = ToStringValue(value);
                                        if (strValue != "-1")
                                        {
                                            string[] strArr = strValue.Split(";".ToCharArray());
                                            for (int index = 0; index < strArr.Length; index++)
                                            {
                                                if (string.IsNullOrEmpty(strArr[index]))
                                                {
                                                    continue;
                                                }

                                                floatArr.Add(float.Parse(strArr[index]));
                                            }
                                        }

                                        value = (floatArr.Count == 0) ? null : floatArr;
                                    }
                                }
                                break;
                        }

                        string fieldName = fieldNameRow[column].ToString();

                        // 表头自动转换成小写
                        if (lowcase)
                        {
                            fieldName = fieldName.ToLower();
                        }

                        if (!string.IsNullOrEmpty(fieldName) &&
                            fieldName.IndexOf("Column") == -1 &&
                            value != null)
                        {
                            rowData[fieldName] = value;
                        }
                    }
                    catch (Exception exp)
                    {
                        throw new Exception(sheet.TableName + ".ID:" + ID.ToString() + ".列:" + column.ToString() + ".值:" + value.ToString() + "类型与定义类型不符");
                    }
                }

                if (m_data.ContainsKey(ID))
                {
                    throw new Exception(sheet.TableName + " " + "ID: " + ID.ToString() + " 重叠");
                }
                m_data[ID] = rowData;
            }
        }

        public string ToStringValue(object value)
        {
            string strValue = "";

            if (value.GetType() == typeof(DBNull))
            {
                return "";
            }
            else if (value.GetType() == typeof(double))
            {
                strValue = value.ToString();
            }
            else
            {
                strValue = (string)value;
            }
            return strValue;
        }

        /// <summary>
        /// 将内部数据转换成Json文本，并保存至文件
        /// </summary>
        /// <param name="jsonPath">输出文件路径</param>
        public void SaveToFile(string filePath, Encoding encoding)
        {
            if (m_data == null)
                throw new Exception("JsonExporter内部数据为空。");

            //-- 转换为JSON字符串
            JsonDataHolder dataHolder = new JsonDataHolder();
            dataHolder.configList = new List<object>(m_data.Values);

            string json = JsonConvert.SerializeObject(dataHolder, Formatting.Indented);

            //-- 保存文件
            using (FileStream file = new FileStream(filePath, FileMode.Create, FileAccess.Write))
            {
                using (TextWriter writer = new StreamWriter(file, encoding))
                {
                    writer.Write(json);
                }
            }
        }
    }
}